<?php

namespace slinks\extensions\action;

use slinks\common\addendum\ReflectionAnnotatedClass;
use slinks\core\dependencyInjectionExt\annotation\ServiceDefiningAnnotationUtil;
use slinks\extensions\action\interceptor\InterceptorStack;
use slinks\extensions\action\configuration\ConfigurationBuilder;
use slinks\core\DependencyInjection\Loader\XmlFileLoader;
use slinks\extensions\action\configuration\ResultConfig;
use slinks\common\Finder\Finder;
use slinks\common\io\AnnotationReader;
use slinks\extensions\action\annotation\ActionDefiningAnnotationVisitor;
use slinks\core\Config\Resource\FileResource;
use slinks\core\DependencyInjection\Definition;
use slinks\core\DependencyInjection\ContainerBuilder;
use slinks\core\dependencyInjectionExt\extension\Extension;
use slinks\extensions\action\core\Configuration;
use slinks\core\Config\FileLocator;

/**
 * 
 * @author Navid Mitchell
 *
 */
class ActionExtension extends Extension {
    const RESULT_PREFIX = 'slinks.action.result.';
    const INTERCEPTOR_PREFIX = 'slinks.action.interceptor.';

    /**
     * Loads action mappings from annotations
     * @param array $config
     * @param ContainerBuilder $container
     */
    public function scanLoad($config, ContainerBuilder $container) {

        $path = $config['path'];

        // add directory as resource
        $container->addResource(new FileResource($path));

        $reader = new AnnotationReader(new ActionDefiningAnnotationVisitor($container, new ConfigurationBuilder($container)));

        $finder = new Finder();

        $reader->read($finder->files()->name('*.php')->in($path));

        $this->initializeConfigurationIfNeeded($container);
    }

    public function configLoad($config, ContainerBuilder $container) {
        $configBuilder = new ConfigurationBuilder($container);

        if (isset($config['defaultResult'])) {
            $configBuilder->setDefaultResultName($config['defaultResult']);
        }

        if (isset($config['defaultInterceptorStack'])) {
            $configBuilder->setDefaultInterceptorStackName($config['defaultInterceptorStack']);
        }
    }

    public function resultLoad($config, ContainerBuilder $container) {

        if (class_exists($config['class'])) {
            $definition = ServiceDefiningAnnotationUtil::createDefinition(new ReflectionAnnotatedClass($config['class']));
        } else {
            $definition = new Definition();
            $def->setClass($config['class']);
            // TODO: log that Annotation based config will not happen.
        }

        $serviceId = self::RESULT_PREFIX . $config['name'];
        $container->setDefinition($serviceId, $definition);

        $configBuilder = new ConfigurationBuilder($container);
        $configBuilder->addResultConfig(new ResultConfig($config['name'], $serviceId));

        $this->initializeConfigurationIfNeeded($container);
    }

    public function interceptorLoad($config, ContainerBuilder $container) {

        if (class_exists($config['class'])) {
            $definition = ServiceDefiningAnnotationUtil::createDefinition(new ReflectionAnnotatedClass($config['class']));
        } else {
            $definition = new Definition();
            $def->setClass($config['class']);
            // TODO: log that Annotation based config will not happen.
        }

        $container->setDefinition(self::INTERCEPTOR_PREFIX . $config['name'], $definition);
    }

    public function interceptorStackLoad($config, ContainerBuilder $container) {
        $configBuilder = new ConfigurationBuilder($container);

        $ref = array();

        // add prefix and keyed numerically as expected by the InterceptorStack.
        foreach ($config['interceptorRef'] as $value) {
            if (is_array($value)) {
                $ref[] = $value['name'] = self::INTERCEPTOR_PREFIX . $value['name'];
            } else {
                $ref[] = $value = self::INTERCEPTOR_PREFIX . $value;
            }
        }

        $configBuilder->addInterceptorStack(new InterceptorStack($config['name'], $container, $ref));
    }

    public function initializeConfigurationIfNeeded(ContainerBuilder $container) {
        if (!$container->hasDefinition('slinks.action.configuration')) {
            $loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/resources/config'));
            $loader->load('session.xml');
            $loader->load('action.xml');
        }
        return $container->getDefinition('slinks.action.configuration');
    }

    /**
     * Returns the base path for the XSD files.
     *
     * @return string The XSD base path
     */
    public function getXsdValidationBasePath() {
        return __DIR__ . '/resources/schema';
    }

    /**
     * Returns the namespace to be used for this extension (XML namespace).
     *
     * @return string The XML namespace
     */
    public function getNamespace() {
        return 'http://www.mitchellsoftware.net/schema/dic/action';
    }

    /**
     * Returns the recommended alias to use in XML.
     *
     * This alias is also the mandatory prefix to use when using YAML.
     *
     * @return string The alias
     */
    public function getAlias() {
        return 'action';
    }

}